#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <rtthread.h>
#include <finsh.h>
#include <dfs_def.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <lzmadec.h>

#include <dfs_fs.h>
#include <dfs_posix.h>

#define CHUNKSIZE_IN  (512*1024)
#define CHUNKSIZE_OUT (1024*1024)
////
////
//// in_file : the compressed file
//// out_file : output original file
int uncompress(const char* in_file, const char* out_file)
{
	int ret;
	lzmadec_stream strm;
	size_t write_size;
	
	if(in_file == RT_NULL || out_file == RT_NULL)
		return -1;
	
	unsigned char *buffer_in  =  rt_malloc (CHUNKSIZE_IN);
	unsigned char *buffer_out =  rt_malloc (CHUNKSIZE_OUT);

	/* Check the command line arguments. */

	if (buffer_in == NULL || buffer_out == NULL) {
		rt_kprintf("malloc error: Not enough memory.\n");
		return 5;
	}

	int in_fd = open(in_file,DFS_O_RDONLY,0);
	if(in_fd >= 0){
	  rt_kprintf("open input file :%s!\n",in_file);
	}else{
		rt_kprintf("open input file error!\n");
		return -1;
	}
	
	int out_fd = open(out_file,DFS_O_RDWR,0);
	if(out_fd >= 0){
		rt_kprintf("open output file :%s!\n",out_file);
	}else{
		rt_kprintf("open output file error!\n");
		return -1;
	}
	
	/* Other initializations */
	strm.lzma_alloc = NULL;
	strm.lzma_free = NULL;
	strm.opaque = NULL;
	strm.avail_in = 0;
	strm.next_in = NULL;
	
	if (lzmadec_init (&strm) != LZMADEC_OK) {
		rt_kprintf ("lzmadec_init() error: Not enough memory.\n");
		return 2;
	}
	
	int start = rt_tick_get();
	
#if 0	
	/* Decode */
	while (1) {
		if (strm.avail_in == 0) {
			strm.next_in = buffer_in;
			strm.avail_in = read (in_fd,buffer_in,CHUNKSIZE_IN);
			rt_kprintf("avail_in=%d\n",strm.avail_in);
		}
		strm.next_out = buffer_out;
		strm.avail_out = CHUNKSIZE_OUT;
		
		ret = lzmadec_decode (&strm, strm.avail_in == 0);
		if (ret != LZMADEC_OK && ret != LZMADEC_STREAM_END){
			rt_kprintf ("lzmadec_decode() error: ret=%d\n",ret);
			return 1;
		}
		
		write_size = CHUNKSIZE_OUT - strm.avail_out;
		if (write_size != (write(out_fd, buffer_out,write_size))){
			rt_kprintf("error write()=%d\n",write_size);
			return 2;
		}
	  rt_kprintf("write_size = %d,strm.avail_out=%d\n",write_size,strm.avail_out);
			
		if (ret == LZMADEC_STREAM_END) {
			lzmadec_end (&strm);
			rt_kprintf("finish uncompress ,cost:%d ms\n",rt_tick_get() - start);
			return 0;
		}
	}
#else // one call interface
	// lzmadec_buffer();    int fd = open(file,DFS_O_RDONLY,0);
	  int fd = open(in_file,DFS_O_RDONLY,0);
    if(fd >= 0){
        struct stat buf;
        stat(in_file, &buf);
        rt_uint32_t file_size = buf.st_size;
        rt_kprintf("check file:%s size: %d Bytes [%d KB]\n",in_file,file_size,file_size / 1024);
        rt_uint8_t *data = (rt_uint8_t *)rt_malloc(file_size);
        if(data == RT_NULL)
            return -6;
        read(fd,data,file_size);
				uint8_t* uncompress_data = rt_malloc(1024*1024);
				size_t uncompress_data_len = 1024*1024;
				lzmadec_buffer(uncompress_data,&uncompress_data_len,data,file_size);
				write(out_fd,uncompress_data,uncompress_data_len);
				rt_kprintf("uncompress %d bytes,cost:%d ms\n",uncompress_data_len,rt_tick_get() - start);
				rt_kprintf("finish uncompress ,cost:%d ms\n",rt_tick_get() - start);
				rt_free(uncompress_data);
		}
#endif
}

FINSH_FUNCTION_EXPORT(uncompress,"uncompress(in,out)");
